﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace System
{
    /*internal class TestLifeTimeScope
    {

        static void Test(System.IO.FileStream inFileStream)
        {
            using (new LifeTimeScope()) // assigns LifeTimeScope.Current = this, pushes on stack
            {
                 int i =theEffort.AddRef().Notes.AddRef().Length;

                 using (new LifeTimeScope()) // assigns LifeTimeScope.Current = this, pushes on stack
                 {
                     int j =theEffort.AddRef().Notes.AddRef().Length;
                 } // calls dispose on wrapper only, and pops stack!        

                int m =theEffort.AddRef().Notes.AddRef().Length;

            } // calls dispose on wrapper only, and pops stack!        
        }
    }*/

    public  class LifeTimeScope : IDisposable              
    {

        private static LifeTimeScope _Current = null;
        private static Stack<LifeTimeScope> theScopeStack  = new Stack<LifeTimeScope>(); // used to show Scope indentiation
        public static LifeTimeScope Current{
          get{
                 return _Current;
            }
         }
        
      
        #region IDisposable Members
        public System.Collections.ArrayList theListOfWrapperObjectsToCallDisposeOn = new System.Collections.ArrayList();

        public LifeTimeScope()
        {
            _Current = this;
            theScopeStack.Push(this);
        }
      
        public void Dispose()
        {
            foreach (IDisposable theObject in theListOfWrapperObjectsToCallDisposeOn)
            {
                theObject.Dispose();
            }
            _Current = theScopeStack.Pop();
        }

        #endregion
    }

     // Do use extension methods to add AddRef() to any IDisposable
     public static class ReferenceCountingExtensions
    {
        static public System.Collections.Generic.Dictionary<object, object>
            theHashOfReferenceCountedClasses = new System.Collections.Generic.Dictionary<object, object>();
        public static T AddRef<T>(this T resource)
        {
            object theObject=null;
            theHashOfReferenceCountedClasses.TryGetValue(resource, out theObject);
            if (theObject == null)
            {
                theObject = new RefCounted<T>(resource);
                theHashOfReferenceCountedClasses[resource] = theObject;
            }
            else
            {
                ((RefCounted<T>)theObject).AddRef();
            }
            System.LifeTimeScope.Current.theListOfWrapperObjectsToCallDisposeOn.Add(theObject);
            return (T) resource;
        }
    }
    /// <summary>
    /// Base Class for a RefCountedUnmanagedResourceProtectingClass
    /// Caution with cyclic use - however
    /// </summary>
    public class RefCounted<T> : IDisposable
    {
        private T theResource;
        bool IsFinalDisposed = false;
        int RefCounter = 0;
        public RefCounted(T inResource)
        {
            theResource = inResource;
            System.Threading.Interlocked.Increment(ref RefCounter);
        }
        public RefCounted<T> AddRef()
        {
            System.Threading.Interlocked.Increment(ref RefCounter);
            return this;
        }
        public T Resource
        {
            get
            {
                return theResource;
            }
        }
        ~RefCounted()
        {
            if (!IsFinalDisposed)
            {
                Dispose();
            }
        }
         public void Dispose()
        {
            System.Threading.Interlocked.Decrement(ref RefCounter);
            if ((RefCounter == 0) && (!IsFinalDisposed)) FinalDispose();
        }
        virtual public void FinalDispose()
        {
		if(theResource.GetType().IsCOMObject){
System.Runtime.InteropServices.Marshal.ReleaseComObject(theResource);
} else {           	
   ((IDisposable)theResource).Dispose();
}
            IsFinalDisposed = true;
        }
    }

    }
